﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Kinectver1._0.CadObject;
using Kinect.Toolbox;
namespace Kinectver1._0
{
    //two hand gesture
    //this function allows us to manage both things!
    public abstract class twoHandGesture : gesture
    {
        public List<gesture> detectedGestures = new List<gesture>(); // these might not have to be lists
        public List<gesture> rightHandGestures = new List<gesture>();
        public List<gesture> leftHandGestures = new List<gesture>();
        public Vector3 right;
        public Vector3 left;


        public double Ep
        {
            get;
            private set;
        }

        public int gestureCount
        {
            get
            {
                return detectedGestures.Count;
            }
        }

        public twoHandGesture(double epsilon = 1000)
        {
            Ep = epsilon;
            rightHandGestures.Clear();
            leftHandGestures.Clear();

        }

        public void add(gesture someGesture)
        {
            someGesture.gestureDectected += gestureDectected;
            detectedGestures.Add(someGesture);

            if (someGesture.hand == "right")
                rightHandGestures.Add(someGesture);
            else
                leftHandGestures.Add(someGesture);
        }

        public void remove(gesture someGesture)
        {
            someGesture.gestureDectected -= gestureDectected;
            gesture rem = detectedGestures[0];
            if (rem.hand == "right")
                rightHandGestures.Remove(rem);
            else
                leftHandGestures.Remove(rem);
            detectedGestures.Remove(rem);
        }

        void gestureDectected(string sgesture)
        {
            verifyGestures(sgesture);
        }

        protected abstract void verifyGestures(string sgesture);


    }

    public class InitGesture : twoHandGesture
    {
        DateTime? firstDetectedGestureTime;
        public Vector3 Origin { set; get; }
        public bool twohandstarted { get; set; } //the checker for two hand starts!

        public InitGesture(double epsilon = 1000)
            : base(epsilon)
        {
            twohandstarted = false;
        }

        public void trigger()
        {
            if (rightHandGestures[0].listings.Count != 0 )
                right = rightHandGestures[0].listings[rightHandGestures[0].listings.Count - 1].Pos;
            if (leftHandGestures[0].listings.Count != 0)
                left = leftHandGestures[0].listings[leftHandGestures[0].listings.Count - 1].Pos;
            if (twohandstarted == false) //initalizer
                initLookForGestures();
            else
            {
                LookForGestures();
            }
        }
        protected bool ScanPositions(Func<Vector3, Vector3, bool> heightFunction, Func<Vector3, Vector3, bool> directionFunction,
            Func<Vector3, Vector3, bool> lengthFunction, int minTime, int maxTime)
        {
            int start = 0;

            for (int i = 1; i < listings.Count - 1; i++)
            {
                if (!heightFunction(listings[0].Pos, listings[i].Pos) || !directionFunction(listings[i].Pos, listings[i + 1].Pos))
                {
                    start = i;
                }
                if (lengthFunction(listings[i].Pos, listings[start].Pos))
                {
                    double totalMilliseconds = (listings[i].Time - listings[start].Time).TotalMilliseconds;
                    if (totalMilliseconds >= minTime && totalMilliseconds <= maxTime)
                    {
                        return true;
                    }
                }
            }

            return false;
        }


        //twohand start, just need to know if the x and y and z are relatively together, direciton doesnt matter
        protected bool twohandstarter(Func<Vector3, Vector3, bool> heightFunction, Func<Vector3, Vector3, bool> widthFunction,
            int minTime)
        {
            int start = 0;
            int count = (rightHandGestures[0].listings.Count + leftHandGestures[0].listings.Count) / 2;

            //check for at least 2;
            if (rightHandGestures[0].listings.Count != leftHandGestures[0].listings.Count)
                return false;
            //height function should be
            //left hand and right hand must be within .2
            for (int i = 1; i < count - 1; i++)
            {
                if (!heightFunction(rightHandGestures[0].listings[i].Pos, leftHandGestures[0].listings[i].Pos) || !widthFunction(rightHandGestures[0].listings[i].Pos, leftHandGestures[0].listings[i].Pos))
                {
                    start = i;
                }
                if (heightFunction(rightHandGestures[0].listings[i].Pos, leftHandGestures[0].listings[i].Pos) && widthFunction(rightHandGestures[0].listings[i].Pos, leftHandGestures[0].listings[i].Pos))
                {
                    //chose on of them to check the time
                    double totalMilliseconds = (rightHandGestures[0].listings[i].Time - rightHandGestures[0].listings[start].Time).TotalMilliseconds;
                    if (totalMilliseconds >= minTime)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        protected bool scanForSquare(Func<Vector3, Vector3, bool> heightFunction, Func<Vector3, Vector3, bool> directionFunction, Func<Vector3, Vector3, bool> angleFunction,
            int minTime, int maxTime)
        {
            int start = 0;
            int count = (rightHandGestures[0].listings.Count + leftHandGestures[0].listings.Count) / 2;

            //check for at least 2;
            if (rightHandGestures[0].listings.Count != leftHandGestures[0].listings.Count)
                return false;
            //height function should be
            //left hand and right hand must be within .2
            for (int i = 1; i < count - 1; i++)
            {
                if (!heightFunction(rightHandGestures[0].listings[i].Pos, leftHandGestures[0].listings[i].Pos) || !directionFunction(rightHandGestures[0].listings[i].Pos, leftHandGestures[0].listings[i].Pos))
                {
                    start = i;
                }
                if (heightFunction(rightHandGestures[0].listings[i].Pos, leftHandGestures[0].listings[i].Pos) && directionFunction(rightHandGestures[0].listings[i].Pos, leftHandGestures[0].listings[i].Pos) && angleFunction(rightHandGestures[0].listings[i].Pos, leftHandGestures[0].listings[i].Pos))
                {
                    //chose on of them to check the time
                    double totalMilliseconds = (rightHandGestures[0].listings[i].Time - rightHandGestures[0].listings[start].Time).TotalMilliseconds;
                    if (totalMilliseconds >= minTime && totalMilliseconds <= maxTime)
                    {
                        return true;
                    }
                }
            }

            return false;
        }
        protected override void LookForGestures()
        {
            if (rightHandGestures[0].listings.Count > 0 && leftHandGestures[0].listings.Count > 0)
            {
                
                //if each one has something check to see if they occured at teh same time.
                //check the last two 
                /*
                int rightCount = rightHandGestures[0].listings.Count;
                int leftCount = leftHandGestures[0].listings.Count;
                
                */
                //too close check
                //if (DateTime.Now.Subtract(lastGestureDate).TotalMilliseconds > minPeriod)
                //{
                //    if ((Math.Abs(right.X - left.X) < 0.01f || Math.Abs(left.X - right.X) < 0.01f) && (Math.Abs(right.Y - left.Y) < 0.01f || Math.Abs(left.Y - right.Y) < 0.01f))
                //    {
                //        //THIS IS WHERE AN OBJECT GETS CREATED!
                //        
                //    }
                //    lastGestureDate = DateTime.Now;
                //}
                if (scanForSquare((p1, p2) => Math.Abs(p1.Y - p2.Y) > 0.2f, //height
                    (p1, p2) => Math.Abs(p1.X - p2.X) > 0.2f, //direction
                    (p1, p2) => Math.Atan2(p1.Y - p2.Y, p1.X - p2.X ) > -2.3f && Math.Atan2(p1.Y - p2.Y, p1.X - p2.X ) < -2.7f, 
                    200,//min
                    1500 //max
                    ))
                {
                    gestureIsDetected("square!");
                    return;
                }

            }
        }
        protected void initLookForGestures()
        {
            if (rightHandGestures[0].listings.Count > 0 && leftHandGestures[0].listings.Count > 0)
            {
                //if each one has something check to see if they occured at teh same time.
                //check the last two 
                /*
                int rightCount = rightHandGestures[0].listings.Count;
                int leftCount = leftHandGestures[0].listings.Count;
                right = rightHandGestures[0].listings[rightCount - 1].Pos;
                left = leftHandGestures[0].listings[leftCount - 1].Pos;*/
                //too close check
                //if (DateTime.Now.Subtract(lastGestureDate).TotalMilliseconds > minPeriod)
                //{
                //    if ((Math.Abs(right.X - left.X) < 0.01f || Math.Abs(left.X - right.X) < 0.01f) && (Math.Abs(right.Y - left.Y) < 0.01f || Math.Abs(left.Y - right.Y) < 0.01f))
                //    {
                //        //THIS IS WHERE AN OBJECT GETS CREATED!
                //        gestureIsDetected("TWOHANDSTART!!!");
                //    }
                //    lastGestureDate = DateTime.Now;
                //}
                if (twohandstarter((p1, p2) => Math.Abs(p1.Y - p2.Y) < 0.2f,
                    (p1, p2) => Math.Abs(p1.X - p2.X) < 0.2f, 1000))
                {
                    twohandstarted = true;
                    return;
                }

            }
        }
        protected override void verifyGestures(string sgesture)
        {
            if (!firstDetectedGestureTime.HasValue || DateTime.Now.Subtract(firstDetectedGestureTime.Value).TotalMilliseconds > Ep)
            {
                firstDetectedGestureTime = DateTime.Now;
                //detectedGesutresName.Clear();
            }
            listings.ForEach(e =>
            {
                if (gesturesCanvas != null)
                    gesturesCanvas.Children.Remove(e.DisplayEllipse);
            });
            listings.Clear();
            //detectedGesutresName.Add(sgesture);
            //check both hands, to see if somethin is tehre
            //if (rightHandGestures[0].listings.Count > 0 && leftHandGestures[0].listings.Count > 0 )
            //{
            //    //if each one has something check to see if they occured at teh same time.
            //    //check the last two 

            //    int rightCount = rightHandGestures[0].listings.Count;
            //    int leftCount = leftHandGestures[0].listings.Count;
            //    right = rightHandGestures[0].listings[rightCount-1].Pos;
            //    left = leftHandGestures[0].listings[leftCount - 1].Pos;

            //    if ((Math.Abs(right.X - left.X) < 0.2f || Math.Abs(left.X - right.X) < 0.2f) && (Math.Abs(right.Y - left.Y) < 0.2f || Math.Abs(left.Y - right.Y) < 0.2f))
            //    {
            //        //THIS IS WHERE AN OBJECT GETS CREATED!
            //        gestureIsDetected("TWOHANDSTART");
            //        this.Origin = right;
            //    }
            //}
        }

    }
}